﻿using AiMoWindows.GHAiMo;
using GH_IO.Serialization;
using System;
using System.Linq;
using System.Text;

namespace AiMoInGH.Connector
{
    class GHScriptSource
    {
        public const double IOVersion = 0.1;
        public string[] Usings { get; set; } = Array.Empty<string>();
        public string[] Mains { get; set; } = Array.Empty<string>();
        public string[] OtherFuncs { get; set; } = Array.Empty<string>();
        public string[] OtherClass { get; set; } = Array.Empty<string>();
        public string[] ExternalAssembliesPaths { get; set; } = Array.Empty<string>();
        public GH_ParamSyntaxNodeInfo[] ParamInfos { get; set; } = new GH_ParamSyntaxNodeInfo[0];
        public bool HasPublicCustomizedClasses { get; } = false;
        public bool NotEmpty => Usings.Length > 0 || Mains.Length > 0 || OtherFuncs.Length > 0 || OtherClass.Length > 0;
        public GHScriptSource()
        {

        }

        public string AllCode()
        {
            string[] parts = CSharpGHTemplateEN.Split(
    separator,
    StringSplitOptions.RemoveEmptyEntries
    );
            string beforeMain = FixNewlines(parts[0]);
            string beforeFunc = FixNewlines(parts[1]);
            string beforeClass = FixNewlines(parts[2]);
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.AppendLine(string.Join(Environment.NewLine, Usings));
            stringBuilder.AppendLine(beforeMain);
            stringBuilder.AppendLine(string.Join(Environment.NewLine, Mains));
            stringBuilder.AppendLine(beforeFunc);
            stringBuilder.AppendLine(string.Join(Environment.NewLine, OtherFuncs));
            stringBuilder.AppendLine(beforeClass);
            stringBuilder.AppendLine(string.Join(Environment.NewLine, OtherClass));
            return stringBuilder.ToString();
        }

        public GHScriptSource(string[] usings, string[] mains, string[] otherFuncs, string[] otherClass, string[] externalReferences, GH_ParamSyntaxNodeInfo[] paramInfos, bool hasPublicCustomizedClasses)
        {
            Usings = usings;
            Mains = mains;
            OtherFuncs = otherFuncs;
            OtherClass = otherClass;
            ExternalAssembliesPaths = externalReferences;
            ParamInfos = paramInfos;
            HasPublicCustomizedClasses = hasPublicCustomizedClasses;
        }

        public void Write(GH_IWriter writer)
        {
            writer.SetInt32("UsingsCount", Usings.Length);
            for (int i = 0; i < Usings.Length; i++)
            {
                writer.SetString("Usings", i, Usings[i]);
            }

            writer.SetInt32("MainsCount", Mains.Length);
            for (int i = 0; i < Mains.Length; i++)
            {
                writer.SetString("Mains", i, Mains[i]);
            }

            writer.SetInt32("OtherFuncsCount", OtherFuncs.Length);
            for (int i = 0; i < OtherFuncs.Length; i++)
            {
                writer.SetString("OtherFuncs", i, OtherFuncs[i]);
            }

            writer.SetInt32("OtherClassCount", OtherClass.Length);
            for (int i = 0; i < OtherClass.Length; i++)
            {
                writer.SetString("OtherClass", i, OtherClass[i]);
            }

            writer.SetInt32("ExternalAssembliesPathsCount", ExternalAssembliesPaths.Length);
            for (int i = 0; i < ExternalAssembliesPaths.Length; i++)
            {
                writer.SetString("ExternalAssembliesPaths", i, ExternalAssembliesPaths[i]);
            }

            string[] paramInfos = GHScriptIO.WriteParamInfos(ParamInfos);
            writer.SetInt32("ParamInfosCount", paramInfos.Length);
            for (int i = 0; i < paramInfos.Length; i++)
            {
                writer.SetString("ParamInfos", i, paramInfos[i]);
            }

        }
        public void Read(GH_IReader reader)
        {
            int usingCount = reader.GetInt32("UsingsCount");
            Usings = new string[usingCount];
            for (int i = 0; i < usingCount; i++)
            {
                Usings[i] = reader.GetString("Usings", i);
            }

            int mainsCount = reader.GetInt32("MainsCount");
            Mains = new string[mainsCount];
            for (int i = 0; i < mainsCount; i++)
            {
                Mains[i] = reader.GetString("Mains", i);
            }

            int otherFuncsCount = reader.GetInt32("OtherFuncsCount");
            OtherFuncs = new string[otherFuncsCount];
            for (int i = 0; i < otherFuncsCount; i++)
            {
                OtherFuncs[i] = reader.GetString("OtherFuncs", i);
            }

            int otherClassCount = reader.GetInt32("OtherClassCount");
            OtherClass = new string[otherClassCount];
            for (int i = 0; i < otherClassCount; i++)
            {
                OtherClass[i] = reader.GetString("OtherClass", i);
            }

            int paramInfosCount = reader.GetInt32("ParamInfosCount");
            string[] paramInfos = new string[paramInfosCount];
            for (int i = 0; i < paramInfosCount; i++)
            {
                paramInfos[i] = reader.GetString("ParamInfos", i);
            }
            ParamInfos = GHScriptIO.ReadParamInfos(paramInfos);
            int externalAssempliesCount = 0;

            if (reader.TryGetInt32("ExternalAssembliesPathsCount", ref externalAssempliesCount))
            {
                string[] externalAssemplies = new string[externalAssempliesCount];
                for (int i = 0; i < externalAssempliesCount; i++)
                {
                    externalAssemplies[i] = reader.GetString("ExternalAssembliesPaths", i);
                }
                ExternalAssembliesPaths = externalAssemplies;
            }
        }


        static readonly string CSharpGHTemplateEN =
@"//This class is running as a grasshopper component 
public class Script_Instance : GHCSharpScriptInstance
{
    //Click [Run] will expire this component and recalculate
    public override void SolveInstance()
    {
//{661C96CD-DE31}
    }//Additional codes of other methods
//{04BE4B3A-3ED4}
}//Additional codes of other class
//{5EFBB44A-673A}
";
        static readonly string[] separator = new string[]
        {
            //public class Script_Instance : CSharpScriptInstance{
            //public override void Main(){
            "//{661C96CD-DE31}",//main
            //}
            "//{04BE4B3A-3ED4}",//funcAddition
            //}
            "//{5EFBB44A-673A}",//classAddition
        };
        static string FixNewlines(string text)
        {
            if (text.Contains('\r') || text.Contains('\n'))
            {
                text = text.Replace("\r\n", "\r");
                text = text.Replace('\n', '\r');
                text = text.Replace("\r", Environment.NewLine);
            }
            return text;
        }
    }
}
